﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Collections;

namespace Tencent.OA.App
{
    /// <summary>
    /// 表示分层的asp.net MVC 站点地图结构（如 SiteMap 类和实现抽象类 SiteMapProvider 的类所描述的结构）中的一个节点。
    /// </summary>
    public class MvcSiteMapNode : SiteMapNode
    {
        private string m_title = "";
        private string m_description;
        private ISiteMapNodeUrlResolver m_urlResolver;
        private ISiteMapNodeVisibilityProvider m_visibilityProvider;
        private MvcSiteMapProvider m_provider;

        /// <summary>
        /// 使用指定的 key 和站点地图提供程序来初始化 MvcSiteMapNode 类的新实例。
        /// </summary>
        /// <param name="provider">与节点关联的 MvcSiteMapProvider。</param>
        /// <param name="key">一个特定于提供程序的查找键。</param>
        public MvcSiteMapNode(MvcSiteMapProvider provider, string key)
            : this(provider, key, new NameValueCollection())
        {
        }

        /// <summary>
        /// 使用指定的 key 和站点地图提供程序以及用于本地化的显式的资源键来初始化 MvcSiteMapNode 类的新实例，
        /// </summary>
        /// <param name="provider">与节点关联的 MvcSiteMapProvider。</param>
        /// <param name="key">一个特定于提供程序的查找键。</param>
        /// <param name="explicitResourceKeys">用于本地化的显式资源键的 NameValueCollection。</param>
        public MvcSiteMapNode(MvcSiteMapProvider provider, string key, NameValueCollection explicitResourceKeys)
            : base(provider, key, "", "", "", new ArrayList(), new NameValueCollection(), explicitResourceKeys, "")
        {
            this.m_provider = provider;
        }

        public override bool IsAccessibleToUser(HttpContext context)
        {
            //bool baseAccessible = base.IsAccessibleToUser(context);
            if (this.VisibilityProvider != null)
                return this.VisibilityProvider.IsVisible(this, context, this.RouteValues);
            return base.IsAccessibleToUser(context);
        }

        ///// <summary>
        ///// 获取或设置节点名称。该名称在整个sitemap文件的节点中必须唯一。
        ///// </summary>
        //public string NodeName
        //{
        //    get { return this["name"] != null ? this["name"] : ""; }
        //    set { this["name"] = value; }
        //}

        /// <summary>
        /// 获取或设置有关路由的名称。
        /// </summary>
        /// <value>路由的名称。</value>
        public string RouteName
        {
            get { return RouteValues.ContainsKey("routeName") && RouteValues["routeName"] != null ? RouteValues["routeName"].ToString() : ""; }
            set { RouteValues["routeName"] = value; }
        }

        /// <summary>
        /// 获取或设置Area的名称。
        /// </summary>
        /// <value>Area的名称。</value>
        public string Area
        {
            get { return RouteValues.ContainsKey("area") && RouteValues["area"] != null ? RouteValues["area"].ToString() : ""; }
            set { RouteValues["area"] = value; }
        }

        /// <summary>
        /// 权限代码
        /// </summary>
        public string OperationCode
        {
            get
            {
                if (this["operationCode"] != null)
                    return this["operationCode"];

                // 然后尝试递归向上级节点查找，找到即返回该值
                MvcSiteMapNode parentNode = this.ParentNode as MvcSiteMapNode;
                while (parentNode != null)
                {
                    if (!string.IsNullOrEmpty(parentNode.OperationCode))
                        return parentNode.OperationCode;
                    parentNode = parentNode.ParentNode as MvcSiteMapNode;
                }
                return string.Empty;
            }
            set { this["operationCode"] = value; }
        }

        /// <summary>
        /// 获取或设置Controller的名称。
        /// </summary>
        /// <value>Controller的名称。首先尝试从当前节点查找，如果已设置值则直接返回；
        /// 然后尝试从父节点查找，如果都不能找到结果则返回String.Empty。</value>
        public string Controller
        {
            get
            {
                // 从当前节点查找
                if (RouteValues.ContainsKey("controller"))
                    return RouteValues["controller"].ToString();

                // 然后尝试递归向上级节点查找，找到即返回
                MvcSiteMapNode parentNode = this.ParentNode as MvcSiteMapNode;
                while (parentNode != null)
                {
                    if (!string.IsNullOrEmpty(parentNode.Controller))
                        return parentNode.Controller;
                    parentNode = parentNode.ParentNode as MvcSiteMapNode;
                }
                return string.Empty;
            }
            set { RouteValues["controller"] = value; }
        }

        /// <summary>
        /// 获取或设置Action的名称。
        /// </summary>
        /// <value>Action的名称。</value>
        public string Action
        {
            get { return RouteValues.ContainsKey("action") ? RouteValues["action"].ToString() : ""; }
            set { RouteValues["action"] = value; }
        }

        public string ImageUrl
        {
            get { return this["imageUrl"] != null ? this["imageUrl"] : ""; }
            set { this["imageUrl"] = value; }
        }

        /// <summary>
        /// 获取或设置链接的目标。
        /// </summary>
        /// <value>The target frame.</value>
        public string LinkTarget
        {
            get { return this["linkTarget"] != null ? this["linkTarget"] : ""; }
            set { this["linkTarget"] = value; }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示该节点是否是菜单项，默认为false。
        /// </summary>
        public bool IsMenu
        {
            get { return this["isMenu"] != null ? bool.Parse(this["isMenu"]) : false; }
            set { this["isMenu"] = value.ToString().ToLowerInvariant(); }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示当前节点仅显示为标题，而不论是否存在子节点菜单。
        /// </summary>
        public bool TitleOnly
        {
            get { return this["titleOnly"] != null ? bool.Parse(this["titleOnly"]) : false; }
            set { this["titleOnly"] = value.ToString().ToLowerInvariant(); }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示当前节点仅显示为标题，而不论是否存在子节点菜单。
        /// </summary>
        public bool ShowMenu
        {
            get { return this["showMenu"] != null ? bool.Parse(this["showMenu"]) : false; }
            set { this["showMenu"] = value.ToString().ToLowerInvariant(); }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示当前节点是否忽略权限控制。
        /// </summary>
        public bool IgnoreRole
        {
            get { return this["ignoreRole"] != null ? bool.Parse(this["ignoreRole"]) : false; }
            set { this["ignoreRole"] = value.ToString().ToLowerInvariant(); }
        }
        
        /// <summary>
        /// 获取或设置一个值，该值指示该节点是否是顶级菜单，默认为false。
        /// </summary>
        public bool IsRootNode
        {
            get;
            set;
        }

        /// <summary>
        /// 获取或设置用于处理使用 ASP.NET 路由所需的键/值对的集合。
        /// </summary>
        /// <value>使用 ASP.NET 路由所需的键/值对的集合。</value>
        [Browsable(false)]
        public IDictionary<string, object> RouteValues { get; set; }

        /// <summary>
        /// 获取或设置 <see cref="T:System.Web.SiteMapNode"/> 对象所代表的页的 URL。
        /// </summary>
        /// <value></value>
        /// <returns>
        /// 该节点所代表的页的 URL。如果已在.sitemap文件中指定url则直接返回该值；
        /// 否则使用UrlResolver属性的ResolveUrl方法根据Area、Controller、Action和RouteValues生成URL。
        /// </returns>
        /// <exception cref="T:System.InvalidOperationException">
        /// UrlResolver属性值为null。
        /// </exception>
        public override string Url
        {
            get
            {
                if (this["url"] != null)
                {
                    return this["url"];
                }

                if (this.UrlResolver == null)
                {
                    throw new InvalidOperationException("未指定当前节点可用的 ISiteMapNodeUrlResolver 实例。");
                }
                return this.UrlResolver.ResolveUrl(this, RouteValues);
            }
            set
            {
                this["url"] = value;
            }
        }

        /// <summary>
        /// 获取或设置 <see cref="T:System.Web.SiteMapNode"/>  对象的标题。
        /// </summary>
        /// <value></value>
        /// <returns>
        /// 一个表示节点标题的字符串。默认值为 <see cref="F:System.String.Empty"/>。
        /// </returns>
        [Localizable(true)]
        public override string Title
        {
            get
            {
                if (m_title != null)
                {
                    return m_title;
                }
                if (Provider.EnableLocalization)
                {
                    var implicitResourceString = GetImplicitResourceString("title");
                    if (implicitResourceString != null && implicitResourceString == this["title"])
                    {
                        return implicitResourceString;
                    }
                    implicitResourceString = GetExplicitResourceString("title", this["title"], true);
                    if (implicitResourceString != null && implicitResourceString == this["title"])
                    {
                        return implicitResourceString;
                    }
                }
                if (this["title"] != null)
                {
                    return this["title"];
                }
                return string.Empty;
            }
            set
            {
                this["title"] = value;
                m_title = value;
            }
        }

        /// <summary>
        /// 获取或设置 <see cref="T:System.Web.SiteMapNode"/> 的描述。
        /// </summary>
        /// <value></value>
        /// <returns>
        /// 一个表示节点的描述的字符串；如果在siteMap文件中未设置该值则返回Title值。
        /// </returns>
        [Localizable(true)]
        public override string Description
        {
            get
            {
                if (m_description != null)
                {
                    return m_description;
                }
                if (Provider.EnableLocalization)
                {
                    var implicitResourceString = GetImplicitResourceString("description");
                    if (implicitResourceString != null && implicitResourceString == this["description"])
                    {
                        return implicitResourceString;
                    }
                    implicitResourceString = GetExplicitResourceString("description", this["description"], true);
                    if (implicitResourceString != null && implicitResourceString == this["description"])
                    {
                        return implicitResourceString;
                    }
                }

                if (this["description"] != null)
                {
                    return this["description"];
                }
                return this.Title;
            }
            set
            {
                this["description"] = value;
                m_description = value;
            }
        }

        /// <summary>
        /// 获取或设置根据controllerName、actionName信息生成Url的解析器。
        /// </summary>
        /// <value>
        /// 如果已通过set操作设置值则直接返回该值；
        /// 如果配置文件中指定了解析器的TypeName，则返回该TypeName对应的类型实例；
        /// 如果都没有设置则返回 null。
        /// </value>
        public ISiteMapNodeUrlResolver UrlResolver
        {
            get
            {
                if (this.m_urlResolver != null)
                    return this.m_urlResolver;

                if (!string.IsNullOrEmpty(this["urlResolver"]))
                {
                    m_urlResolver = MvcSiteMapProvider.CreateTypeInstance<ISiteMapNodeUrlResolver>(this["urlResolver"]);
                    return m_urlResolver;
                }
                return null;
            }
            set
            {
                m_urlResolver = value;
                if (value != null)
                {
                    this["urlResolver"] = value.GetType().AssemblyQualifiedName;
                }
                else
                {
                    this["urlResolver"] = null;
                }
            }
        }

        /// <summary>
        /// Gets or sets the visibility provider.
        /// </summary>
        /// <value>The visibility provider.</value>
        public ISiteMapNodeVisibilityProvider VisibilityProvider
        {
            get
            {
                if (this.m_visibilityProvider != null)
                    return this.m_visibilityProvider;

                if (!string.IsNullOrEmpty(this["visibilityProvider"]))
                {
                    m_visibilityProvider = MvcSiteMapProvider.CreateTypeInstance<ISiteMapNodeVisibilityProvider>(this["visibilityProvider"]);
                    return m_visibilityProvider;
                }
                return null;
            }
            set
            {
                m_visibilityProvider = value;
                if (value != null)
                {
                    this["visibilityProvider"] = value.GetType().AssemblyQualifiedName;
                }
                else
                {
                    this["visibilityProvider"] = null;
                }
            }
        }

        #region ICloneable

        /// <summary>
        /// 创建作为当前节点副本的新节点。
        /// </summary>
        /// <returns>
        /// 作为当前节点副本的新节点。
        /// </returns>
        public override SiteMapNode Clone()
        {
            return Clone(Key);
        }

        /// <summary>
        /// 根据当前节点的 Key 创建作为当前节点副本的新节点。
        /// </summary>
        /// <param name="key">当前节点的 Key 。</param>
        /// <returns>
        /// 作为当前节点副本的新节点。
        /// </returns>
        public virtual SiteMapNode Clone(string key)
        {
            MvcSiteMapNode clone = new MvcSiteMapNode((Provider as MvcSiteMapProvider), key, new NameValueCollection());
            if (RouteValues != null)
            {
                clone.RouteValues = new Dictionary<string, object>(RouteValues);
            }
            if (Attributes != null)
            {
                clone.Attributes = new NameValueCollection(Attributes);
            }
            if (Roles != null)
            {
                clone.Roles = new ArrayList(Roles);
            }
            //clone.NodeName = NodeName;
            clone.Title = Title;
            clone.Description = Description;
            clone.IsMenu = IsMenu;
            clone.TitleOnly = TitleOnly;
            clone.ShowMenu = ShowMenu;
            clone.LinkTarget = LinkTarget;

            return clone;
        }

        #endregion

    }
}
